package com.ywdnf.gomoku.web.control;

import com.ywdnf.gomoku.ai.AIPlayer;
import com.ywdnf.gomoku.configuration.ThreadPoolExecutorFactory;
import com.ywdnf.gomoku.model.Result;
import com.ywdnf.gomoku.model.chess.Chessman;
import com.ywdnf.gomoku.model.chess.Game;
import com.ywdnf.gomoku.model.chess.GameState;
import com.ywdnf.gomoku.model.chess.Player;
import com.ywdnf.gomoku.model.chess.Point;
import com.ywdnf.gomoku.model.chess.Role;
import com.ywdnf.gomoku.model.chess.Round;
import com.ywdnf.gomoku.model.message.ConfirmMsgBean;
import com.ywdnf.gomoku.util.CommonUtil;
import com.ywdnf.gomoku.util.Const;
import com.ywdnf.gomoku.util.CookieUtil;
import com.ywdnf.gomoku.util.GmkMsgUtils;
import com.ywdnf.gomoku.util.ResultUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * TODO
 *
 * @author lss
 * @date 2019-06-26, Wed
 */
@RestController
@RequestMapping("/api/gomoku")
public class GomokuController {

  /**
   * 临时所有游戏集合
   */
  private static ConcurrentHashMap<String, Game> games = new ConcurrentHashMap<>();

  @GetMapping("/create")
  public Result<?> createGomoku(@RequestParam("u-nick") String userNick, @RequestParam("g-name") String gmkName,
      @RequestParam("g-hide") String hide,
      HttpServletResponse response, HttpServletRequest request) throws IOException, ServletException {

    Game g = new Game(gmkName, StringUtils.isEmpty(hide) || "1".equals(hide));
    Player p1 = new Player(g.getGameId(), userNick, Role.CREATOR);
    g.setCreator(p1);
    g.setPlayer1(p1);
    CookieUtil.setCookie(response, Const.USER_COOKIE_ATTR_KEY, p1.getUserId());
    putGame(g);
    return ResultUtils.newSuccessfulResult(CommonUtil.getReturnUrlToGmk(g.getGameId(), p1.getUserId(), null), null);
  }

  @GetMapping("/create/ai")
  public Result<?> createManMachineBattle(@RequestParam(value = "u-nick", required = false) String userNick,
      @RequestParam(value = "g-name", required = false) String gmkName, HttpServletResponse response)
      throws UnsupportedEncodingException {
    Game g = new Game(gmkName, true, true);
    Player man = new Player(g.getGameId(), userNick, Role.CREATOR);
    Player machine = new AIPlayer(g.getGameId());
    g.setPlayer1(man);
    g.setCreator(man);
    g.setPlayer2(machine);
    CookieUtil.setCookie(response, Const.USER_COOKIE_ATTR_KEY, man.getUserId());
    putGame(g);
    return ResultUtils.newSuccessfulResult(
        CommonUtil.getReturnUrlToGmk(g.getGameId(), man.getUserId(), null),
        null);

  }

  @GetMapping("/join")
  public Result<?> joinGomoku(@RequestParam("u-nick") String userNick, @RequestParam("g-id") String briefGameId)
      throws IOException, ServletException {

    if (StringUtils.isEmpty(briefGameId)) {
      return ResultUtils.newFailedResult("游戏编号不能为空");
    }
    Game game = getGame(CommonUtil.getFullGameId(briefGameId).toUpperCase());
    if (game == null) {
      return ResultUtils.newFailedResult("不存在此编号的游戏");
    }
    if (game.getPlayer1() != null && game.getPlayer2() != null) {
      return ResultUtils.newFailedResult("游戏人数已满，无法加入");
    }
    if (game.getState() != GameState.WAITING_FOR_START) {
      return ResultUtils.newFailedResult("游戏正在进行中，无法加入");
    }
    Player pc2 = new Player(game.getGameId(), userNick, Role.Participant);
    game.setPlayer2(pc2);
    ThreadPoolExecutorFactory.getThreadPoolExecutor().execute(() -> GmkMsgUtils.sendCreatorPlayerIn(game));
    return ResultUtils
        .newSuccessfulResult(CommonUtil.getReturnUrlToGmk(game.getGameId(), pc2.getUserId(), null), null);
  }

  @GetMapping("/start")
  public Result<?> startRound(@RequestParam(Const.PARAM_GAME_ID_IN_URL) String gameId) {
    if (StringUtils.isEmpty(gameId)) {
      return ResultUtils.newFailedResult("非法操作");
    }
    Game game = getGame(gameId);
    if (game == null) {
      return ResultUtils.newFailedResult("非法操作");
    }
    if (game.getPlayer1() == null || game.getPlayer2() == null) {
      return ResultUtils.newFailedResult("人数不足，无法开始");
    }
    if (game.state == GameState.RUNNING) {
      return ResultUtils.newFailedResult("游戏已经开始！");
    }
    game.setState(GameState.RUNNING);
    Round round = new Round();

    // 通知游戏开始
    if (game.isAiGame()) {
      Player oldAiPlayer = game.getPlayer2();
      AIPlayer newPlayer = new AIPlayer(gameId);

      newPlayer.setNick(oldAiPlayer.getNick());
      newPlayer.setUserId(oldAiPlayer.getUserId());
      newPlayer.setRole(Role.Participant);

      game.setPlayer2(newPlayer);
      game.setCurrentRound(round);
      GmkMsgUtils.sendStartGameMsg(game);
      putGame(game);
      if (round.getCurOptPlayer() == newPlayer) {
        newPlayer.autoPlace();
        round.setCurOptPlayer(game.getCreator());
        GmkMsgUtils.sendPlaceChessMsg(game.getCreator());
        return ResultUtils.newSuccessfulResult();
      }
    } else {
      game.setCurrentRound(round);
      GmkMsgUtils.sendStartGameMsg(game);
    }
    // 通知先手玩家落子
    GmkMsgUtils.sendPlaceChessMsg(round.getCurOptPlayer());
    return ResultUtils.newSuccessfulResult();
  }

  @GetMapping("/reset")
  public Result<?> startRound(@RequestParam(Const.PARAM_GAME_ID_IN_URL) String gameId,
      @RequestParam(Const.PARAM_USER_ID_IN_URL) String userId,
      HttpServletRequest request) {
    if (StringUtils.isEmpty(gameId) || StringUtils.isEmpty(userId)) {
      return ResultUtils.newFailedResult("非法操作");
    }

    Game game = getGame(gameId);
    if (game == null) {
      return ResultUtils.newFailedResult("非法操作");
    }
    if (!game.getCreator().getUserId().equals(userId)) {
      return ResultUtils.newFailedResult("非法操作");
    }

    game.setState(GameState.RUNNING);
    Round round = new Round();
    if (game.isAiGame()) {
      Player oldPlayer = game.getPlayer2();
      AIPlayer newAiPlayer = new AIPlayer(gameId);
      newAiPlayer.setNick(oldPlayer.getNick());
      newAiPlayer.setUserId(oldPlayer.getUserId());
      game.setPlayer2(newAiPlayer);
      System.out.println(newAiPlayer);
      oldPlayer = null;
      game.setCurrentRound(round);
      putGame(game);
      GmkMsgUtils.sendStartGameMsg(game);
      if (round.getCurOptPlayer() == newAiPlayer) {
        newAiPlayer.autoPlace();
        round.setCurOptPlayer(game.getCreator());
        GmkMsgUtils.sendPlaceChessMsg(game.getCreator());
        return ResultUtils.newSuccessfulResult();
      }

    } else {
      game.setCurrentRound(round);
      GmkMsgUtils.sendStartGameMsg(game);
    }
    // 通知游戏开始
    // GmkMsgUtils.sendStartGameMsg(game);
    // 通知先手玩家落子
    GmkMsgUtils.sendPlaceChessMsg(round.getCurOptPlayer());
    return ResultUtils.newSuccessfulResult();
  }

  @GetMapping("/surrender")
  public Result<?> surrenderRound(@RequestParam(Const.PARAM_GAME_ID_IN_URL) String gameId,
      @RequestParam(Const.PARAM_USER_ID_IN_URL) String userId) {
    if (StringUtils.isEmpty(gameId) || StringUtils.isEmpty(userId)) {
      return ResultUtils.newFailedResult("非法操作");
    }
    Game game = getGame(gameId);
    if (game == null) {
      return ResultUtils.newFailedResult("非法操作");
    }
    game.setState(GameState.PAUSE);
    Round currentRound = game.getCurrentRound();
    Player winner = CommonUtil.getOthPlayer(userId, game);
    if (winner != null) {
      currentRound.setWinner(winner);
      GmkMsgUtils.sendRoundResultMsg(game, currentRound);
      GmkMsgUtils.sendWinnerSurrenderMsg(winner);
      return ResultUtils.newSuccessfulResult();
    }
    return ResultUtils.newFailedResult("认输失败");
  }

  @GetMapping("/withdrawReq")
  public Result<?> withdrawRequest(@RequestParam(Const.PARAM_GAME_ID_IN_URL) String gameId,
      @RequestParam(Const.PARAM_USER_ID_IN_URL) String userId) {
    if (StringUtils.isEmpty(gameId) || StringUtils.isEmpty(userId)) {
      return ResultUtils.newFailedResult("非法操作");
    }
    Game game = getGame(gameId);
    if (game == null) {
      return ResultUtils.newFailedResult("非法操作");
    }
    // GmkMsgUtils.send(gameId, userId, "123");
    Player othPlayer = CommonUtil.getOthPlayer(userId, game);
    if (othPlayer == null) {
      return ResultUtils.newFailedResult("对方不在线");
    }
    if (game.isAiGame()) {
      // TODO 特殊处理
      return ResultUtils.newSuccessfulResult();
    }
    ConfirmMsgBean msgBean = new ConfirmMsgBean();
    msgBean.setBiz("withdrawCon?gameId=" + gameId + "&withdrawUserId=" + userId);
    msgBean.setTitle("提示");
    msgBean.setBody("对方想要悔棋，是否同意");
    msgBean.setConfirmText("准了");
    msgBean.setCancelText("我不同意");
    msgBean.setType("info");
    GmkMsgUtils.sendPlayerConfirmMsg(gameId, othPlayer.getUserId(), msgBean);
    return ResultUtils.newSuccessfulResult();
  }

  @GetMapping("/withdrawCon")
  public Result<?> withdrawConfirm(@RequestParam(Const.PARAM_GAME_ID_IN_URL) String gameId,
      @RequestParam(value = "withdrawUserId") String withdrawUserId, boolean agree) {
    if (StringUtils.isEmpty(gameId) || StringUtils.isEmpty(withdrawUserId)) {
      return ResultUtils.newFailedResult("非法操作");
    }
    Game game = getGame(gameId);
    if (game == null) {
      return ResultUtils.newFailedResult("非法操作");
    }
    Player confirmUser = CommonUtil.getOthPlayer(withdrawUserId, game);
    if (confirmUser == null) {
      return ResultUtils.newFailedResult("用户已经离开了房间...");
    }
    if (!agree) {
      GmkMsgUtils.sendPlayerMessage(gameId, confirmUser.getUserId(), "对方无情的拒绝了你，并说下不过就赶快投降");
    } else {
      Player withdrawUser = CommonUtil.getSelfPlayer(withdrawUserId, game);
      if (withdrawUser == null) {
        return ResultUtils.newFailedResult("想要悔棋的用户已经离开了房间...");
      }
      List<Point> points = game.getCurrentRound().getCurLayout().backToLastMove(withdrawUser);
      if (points.isEmpty()) {
        GmkMsgUtils.sendPlayerMessage(gameId, confirmUser.getUserId(), "当前没有棋子可以反悔");
        GmkMsgUtils.sendPlayerMessage(gameId, withdrawUserId, "当前没有棋子可以反悔");
      } else {
        List<Chessman> chessmanList = points.stream().map(v -> new Chessman(v, null)).collect(Collectors.toList());
        // 发送删除棋子请求
        GmkMsgUtils.sendRemoveChessMsg(game, chessmanList);
        GmkMsgUtils.sendPlayerMessage(gameId, confirmUser.getUserId(), "对方同意了你的悔棋请求，并觉得你很菜");
        // 通知悔棋用户落子
        game.getCurrentRound().setCurOptPlayer(withdrawUser);
        GmkMsgUtils.sendPlaceChessMsg(withdrawUser);
      }
    }
    return ResultUtils.newSuccessfulResult();
  }


  private static void putGame(Game game) {
    games.put(game.getGameId(), game);
  }

  private static void updateGameInfo(Game game) {
    putGame(game);
  }

  public static Game getGame(String gameId) {
    return games.get(gameId);
  }

  public static ConcurrentHashMap<String, Game> getAll() {
    return games;
  }


}
